#!/usr/bin/env python3

'''
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
'''

'''
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.
    
    To request the provided software under a different license you can contact us at
    support@xoronos.com
'''

import os
import sys
import re
import json

def string_to_matrix(input_string):
    matrix = []
    lines = input_string.split('\n')
    for line in lines:
        words = line.split()
        matrix.append(words)
    return matrix

def split_list_in_configurations_and_command (input_list):
    configurations=[]
    command=[]
    first_conf = 0
    conf_row = 0
    conf_cmd = 0
    # create arrays for configurations and command
    for word in input_list :
        # configuration
        if re.match("^--.*-conf$", word):
             if first_conf == 0:
                 first_conf = 1
                 if conf_row >= len(configurations):
                     configurations.append([])
             else :
                 conf_row = conf_row + 1
                 if conf_row >= len(configurations):
                     configurations.append([])
             configurations[conf_row].append( word[2:] )
        # command
        elif re.match("^--", word):
             conf_cmd = 1
             command.append( word[2:] )
        # option
        else :
             if conf_cmd == 0 :
                 if conf_row >= len(configurations):
                     configurations.append([])
                 configurations[conf_row].append(word[1:])
             else :
                 command.append( word[1:] )
    return configurations, command


def create_json_string_template(tool_name,input_list):
    configurations, command = split_list_in_configurations_and_command(input_list)
    json_str = '{"tool": "'+tool_name+'",\n"configurations":[\n'
    if not configurations :
        json_str=json_str+'],\n'
    else :
        # create json for configurations
        for j, row in enumerate(configurations) :
            for i, word in enumerate(row):
                if i == 0 :
                    json_str = json_str + '{ "name" : "'+row[i]+'",\n"options":[\n'
                elif i == len(row) - 1 :
                    json_str = json_str + '{ "name" : "'+row[i]+'","value":null}\n'
                else :
                    json_str = json_str + '{ "name" : "'+row[i]+'","value":null},\n'
            if j != len(configurations) - 1 :
                json_str = json_str + ']},\n'
            else :
                json_str = json_str + ']}],\n'
    # create json for command
    json_str = json_str + '"command":['
    for i, word in enumerate(command) :
        if i == 0 :
            json_str = json_str + '{ "name" : "'+word+'",\n"options":[\n'
        elif i == len(command) - 1 :
            json_str = json_str + '{ "name" : "'+word+'","value":null}\n'
        else :
            json_str = json_str + '{ "name" : "'+word+'","value":null},\n'
    json_str = json_str + ']}]}'
    return json_str

def populate_json_string(cmd_words,json_str):
    for i, word in enumerate(cmd_words) :
       # match for options excluding the last word
       if (( i != len(cmd_words) - 1 ) and ( not re.match("^--", word) ) and ( re.match("^-", word) )):
           # if the following word is not an option or a command
           if (( not re.match("^--", cmd_words[i+1]) ) and ( not re.match("^-", cmd_words[i+1]) )):
               match = '"name" : "'+word[1:]+'","value":null'
               replace = '"name" : "'+word[1:]+'","value":"'+cmd_words[i+1]+'"'
               json_str = json_str.replace(match, replace)
           else :
               match = '"name" : "'+word[1:]+'","value":null'
               replace = '"name" : "'+word[1:]+'","value":"void"'
               json_str = json_str.replace(match, replace)
    return json_str

def str2json_cmd ( cmd_str ) :

    cmd_words = cmd_str.split()

    if cmd_words[0] == "xrnlib-cli" :

        # get matrix of commands options
        cmd = "xrnlib-cli --help | sed 's/#.*$//g' | grep xrnlib | xargs -I + sh -c \"eval + | sed -n '/help page associated/,/a valid example could be/p ' | sed '1d;$d' | cut -c 1-51 |  grep '-' | tr -d ' ' | tr -s '\\n' ' ' | sed 's/$/\\n/' \""
        commands_and_options_str = os.popen( cmd ).read()
        matrix = string_to_matrix( commands_and_options_str )

        # get the command
        command = ""
        for word in cmd_words :
            if re.match("^--", word) :
                command = word

        # get the row
        cmd_row = []
        idx = 0
        for row in matrix :
            for word in row :
                if command == word :
                    cmd_row = matrix[idx]
            idx = idx + 1 

        # get the json string
        json_str = create_json_string_template("xrnlib-cli",cmd_row)
        json_str = populate_json_string(cmd_words,json_str)
        json_obj = json.loads(json_str)
        json_dump = json.dumps(json_obj, sort_keys=False, indent=2)
        return json_dump

    elif cmd_words[0] == "xrnconv-cli" :
        if (( cmd_words[1] != "--std2xrn" ) and (cmd_words[1] != "--xrn2std")) :
             return ""
        json_str = "{ \"tool\": \"" + cmd_words[0] + "\", \"configurations\": [], \"command\": [ { \"name\": \""
        json_str = json_str + cmd_words[1][2:] + "\", \"options\": ["
        option_value_content = 0 # 0 -> option 1 -> content
        for cmd in cmd_words[2:] :
            if option_value_content == 0 :
                json_str = json_str + "{ \"name\": \"" + cmd[1:] + "\", "
                option_value_content = 1
            elif option_value_content == 1 :
                json_str = json_str + "  \"value\": \"" + cmd + "\" }, "
                option_value_content = 0
        json_str = json_str[:-2] + " ] } ] }"
        json_obj = json.loads(json_str)
        json_dump = json.dumps(json_obj, sort_keys=False, indent=2)
        return json_dump

    elif cmd_words[0] == "xrngen-cli" :
        if (( cmd_words[1] != "--png" ) and (cmd_words[1] != "--flac")) :
             return ""
        json_str = "{ \"tool\": \"" + cmd_words[0] + "\", \"configurations\": [], \"command\": [ { \"name\": \""
        json_str = json_str + cmd_words[1][2:] + "\", \"options\": ["
        option_value_content = 0 # 0 -> option 1 -> content
        for cmd in cmd_words[2:] :
            if option_value_content == 0 :
                json_str = json_str + "{ \"name\": \"" + cmd[1:] + "\", "
                if ((cmd != "-auto-prompt") or (cmd != "-no-prompt")) :
                    option_value_content = 1
                else :
                    json_str = json_str + "  \"value\": \"void\" }, "
            elif option_value_content == 1 :
                json_str = json_str + "  \"value\": \"" + cmd + "\" }, "
                option_value_content = 0
        json_str = json_str[:-2] + " ] } ] }"
        json_obj = json.loads(json_str)
        json_dump = json.dumps(json_obj, sort_keys=False, indent=2)
        return json_dump

def json_cmd2str ( json_cmd ) :
    # reformat json string
    json_obj = json.loads(json_cmd)
    json_cmd = json.dumps(json_obj, sort_keys=False, indent=2)
    json_str = json_cmd.replace("\n"," ")
    json_str = re.sub(' +', ' ', json_str)
    # divide string in three parts
    tool_sub_str, reminder_str = json_str.split('"configurations"')
    configuration_sub_str, reminder_str = reminder_str.split( '"command"')
    command_sub_str = reminder_str
    # get tool name
    tool_str = re.sub('^.*:','',tool_sub_str).replace('"','').replace(',','').replace(' ','')
    cmd_str = tool_str + ' '
    # get configurations
    if tool_str == "xrnlib-cli" :
        configuration_sub_str = configuration_sub_str.split("} ] },")
        for configuration in configuration_sub_str:
            first_option = 0
            # separate name from options
            configuration_name_tmp , options_tmp = configuration.split('"options"')
            # get configuration name
            configuration_name = ('--' + re.sub('^.*:','',configuration_name_tmp).replace('"','').replace(',','')).replace(' ','')
            options_split = options_tmp.split("},")
            for option in options_split :
                if "null" not in option :
                    if "void" in option :
                        if ( first_option == 0 ) :
                            cmd_str = cmd_str + configuration_name + ' '
                        first_option = 1
                        option_name_tmp = option.split(',')[0]
                        option_name =  '-'+re.sub('^.*:','',option_name_tmp).replace('"','').replace(',','').replace(' ','')
                        cmd_str = cmd_str + option_name + ' '
                    else :
                        if ( first_option == 0 ) :
                            cmd_str = cmd_str + configuration_name + ' '
                        first_option = 1
                        option_name_tmp, option_value_tmp = option.split(',')
                        option_name =  '-'+re.sub('^.*:','',option_name_tmp).replace('"','').replace(',','').replace(' ','')
                        cmd_str = cmd_str + option_name + ' '
                        option_value =  re.sub('^.*:','',option_value_tmp).replace('"','').replace(',','').replace(' ','')
                        cmd_str = cmd_str + option_value + ' '
    command_name_tmp, command_options_tmp = command_sub_str.split('", "options":')
    command_name = " --" + re.sub('^.*:','',command_name_tmp).replace('"','').replace(',','').replace(' ','')
    cmd_str = cmd_str + command_name 
    options_tmp = command_options_tmp.split('}, {') 
    for option_tmp in options_tmp :
         name_tmp, value_tmp = option_tmp.split(',')
         name_str = " -" + re.sub('^.*:','',name_tmp).replace('"','').replace(',','').replace(' ','').replace('[','').replace('}','').replace(']','')
         value_str = " " + re.sub('^.*:','',value_tmp).replace('"','').replace(',','').replace(' ','').replace('[','').replace('}','').replace(']','')
         if ( value_str != 'null' ):
             cmd_str = cmd_str + name_str + value_str
    return cmd_str 

################
# Parser lexer #
################

tool_name_str = "xrntranslate-cli"
json2cmd_str = "--json2cmd"
cmd2json_str = "--cmd2json"
jsoncmd_str = "-json"

def print_help():
    print("\nhelp page for the {} command\n".format(tool_name_str))
    print("to create a json file from a xrnlib-cli, xrnconv-cli or xrngen-cli command")
    print("{} {} {} file.json xrnlib-cli  .... ".format(tool_name_str,cmd2json_str, jsoncmd_str))
    print("{} {} {} file.json xrnconv-cli .... ".format(tool_name_str,cmd2json_str, jsoncmd_str))
    print("{} {} {} file.json xrngen-cli  .... \n".format(tool_name_str,cmd2json_str, jsoncmd_str))
    print("to create a string command to standard output from a json file")
    print("{} {} {} file.json \n".format(tool_name_str, json2cmd_str, jsoncmd_str ))

if ( len(sys.argv) < 4 ):
    print("the first argument should be either {} or {}".format(cmd2json_str, json2cmd_str ))
    print("the second argument should be {}".format( jsoncmd_str ))
    print("the third argument should be a json file")
    print_help()
    exit(-1)
if (( sys.argv[1] != cmd2json_str ) and ( sys.argv[1] != cmd2json_str ) and ( sys.argv[2] != jsoncmd_str ) ):
    print("the first argument should be either {} or {}".format(cmd2json_str, json2cmd_str ))
    print("the second argument should be {}".format( jsoncmd_str ))
    print("the third argument should be a json file")
    print_help()
    exit(-1)

if ( sys.argv[1] == cmd2json_str ) :

    # Get all the command line arguments except the script name
    arguments = sys.argv[4:]

    # Concatenate them into a single string
    command_string = ' '.join(arguments)

    # Create dump
    json_dump = str2json_cmd ( command_string )

    # Write the concatenated string to the specified file
    with open(sys.argv[3], 'w') as file:
        file.write(json_dump)    

elif ( sys.argv[1] == json2cmd_str ) :

    # Open the file in read mode
    with open(sys.argv[3], 'r') as file:
        # Read the entire file content into a string
        json_dump = file.read()

    command_string = json_cmd2str ( json_dump )
    print ( command_string )
